/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core;
import java.awt.*;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.beans.*;
import java.text.MessageFormat;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.EmptyBorder;
import org.openide.*;
import org.openide.actions.*;
import org.openide.awt.SplittedPanel;
import org.openide.awt.ToolbarToggleButton;
import org.openide.loaders.*;
import org.openide.explorer.*;
import org.openide.explorer.view.BeanTreeView;
import org.openide.explorer.view.TreeView;
import org.openide.explorer.propertysheet.PropertySheet;
import org.openide.explorer.propertysheet.PropertySheetView;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.WeakListener;
import org.openide.util.actions.SystemAction;
import org.openide.util.io.NbMarshalledObject;
import org.openide.util.RequestProcessor;
import org.openide.windows.CloneableTopComponent;
import org.openide.windows.Workspace;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.netbeans.core.windows.WellKnownModeNames;
import org.netbeans.core.windows.DeferredPerformer;
import org.netbeans.core.windows.WindowManagerImpl;
/** Main explorer - the class remains here for backward compatibility
* with older serialization protocol. Its responsibilty is also
* to listen to the changes of "roots" nodes and open / close
* explorer's top components properly.
*
* @author Ian Formanek, David Simonek, Jaroslav Tulach
*/
public final class NbMainExplorer extends CloneableTopComponent
implements DeferredPerformer.DeferredCommand {
static final long serialVersionUID=6021472310669753679L;
// static final long serialVersionUID=-9070275145808944151L;
/** The message formatter for Explorer title */
private static MessageFormat formatExplorerTitle;
/** holds list of roots (Node) */
private List prevRoots;
/** assignes to each node one top component holding explorer panel
* (Node, ExplorerTab) */
private Map rootsToTCs;
/** currently selected node */
private Node currentRoot;
/** Listener which tracks changes on the root nodes (which are displayed as tabs) */
private transient RootsListener rootsListener;
/** weak roots listener */
private transient PropertyChangeListener weakRootsL;
/** true if listener to ide setiings properly initialized */
private transient boolean listenerInitialized;
/** Minimal initial height of this top component */
public static final int MIN_HEIGHT = 150;
/** Default width of main explorer */
public static final int DEFAULT_WIDTH = 350;
/** Default constructor */
public NbMainExplorer () {
// listening on changes of roots
rootsListener = new RootsListener();
weakRootsL = WeakListener.propertyChange(rootsListener, TopManager.getDefault());
TopManager.getDefault().addPropertyChangeListener(weakRootsL);
}
public HelpCtx getHelpCtx () {
return ExplorerPanel.getHelpCtx (getActivatedNodes (),
new HelpCtx (NbMainExplorer.class));
}
/** Overriden to open all top components of main explorer and
* close this top component, as this top component exists only because of
* backward serialization compatibility.
* Performed with delay, when WS is in consistent state. */
public void open (Workspace workspace) {
WindowManagerImpl.deferredPerformer().putRequest(this, workspace);
}
/** Implementation of DeferredPerformer.DeferredCommand.
* Serves both for refresh roots and old explorer open requests */
public void performCommand (Object context) {
if (context == null) {
// refresh roots request
refreshRoots ();
} else {
// old explorer open request
Workspace workspace = (Workspace)context;
super.open(workspace);
close(workspace);
// now open new main explorer top components
NbMainExplorer singleton = NbMainExplorer.getExplorer();
singleton.openRoots(workspace);
}
}
/** Open all main explorer's top components on current workspace */
public void openRoots () {
openRoots(TopManager.getDefault().getWindowManager().getCurrentWorkspace());
}
/** Open all main explorer's top components on given workspace */
public void openRoots (Workspace workspace) {
// save the tab we should activate
ExplorerTab toBeActivated = MainTab.lastActivated;
// perform open operation
refreshRoots();
Node[] rootsArray = (Node[])getRoots().toArray(new Node[0]);
TopComponent tc = null;
for (int i = 0; i < rootsArray.length; i++) {
tc = getRootPanel(rootsArray[i]);
if (tc != null) {
tc.open(workspace);
}
}
// set focus to saved last activated tab or repository tab
if (toBeActivated == null) {
toBeActivated = getRootPanel(rootsArray[0]);
}
final ExplorerTab localActivated = toBeActivated;
SwingUtilities.invokeLater(new Runnable () {
public void run () {
localActivated.requestFocus();
}
});
}
/** Refreshes current state of main explorer's top components, so they
* will reflect new nodes. Called when content of "roots" nodes is changed.
*/
final void refreshRoots () {
// attach listener to the ide settings if possible
if (!listenerInitialized) {
IDESettings ideS = (IDESettings)IDESettings.findObject(IDESettings.class);
if (ideS != null) {
ideS.addPropertyChangeListener(weakRootsL);
listenerInitialized = true;
}
}
List curRoots = getRoots ();
// first of all we have to close top components for
// the roots that are no longer present in the roots content
if (prevRoots != null) {
HashSet toRemove = new HashSet(prevRoots);
toRemove.removeAll(curRoots);
// ^^^ toRemove now contains only roots that are used no more
for (Iterator it = rootsToTCs.entrySet().iterator(); it.hasNext(); ) {
Map.Entry me = (Map.Entry)it.next();
Node r = (Node)me.getKey();
if (toRemove.contains(r)) {
// close top component asociated with this root context
// on all workspaces
closeEverywhere((TopComponent)me.getValue());
}
}
} else {
// initialize previous roots list
prevRoots();
}
// create and open top components for newly added roots
List workspaces = whereOpened(
(TopComponent[])rootsToTCs().values().toArray(new TopComponent[0])
);
for (Iterator iter = curRoots.iterator(); iter.hasNext(); ) {
Node r = (Node)iter.next();
ExplorerTab tc = getRootPanel(r);
if (tc == null) {
// newly added root -> create new TC and open it on every
// workspace where some top compoents from main explorer
// are already opened
tc = createTC(r);
for (Iterator iter2 = workspaces.iterator(); iter2.hasNext(); ) {
tc.open((Workspace)iter2.next());
}
}
}
// save roots for use during future changes
prevRoots = curRoots;
// now select the right component
// PENDING
/*ExplorerTab tab = getRootPanel (currentRoot);
if (tab == null) {
// root not found
currentRoot = (Node)roots.get (0);
tabs.setSelectedIndex (0);
} else {
tabs.setSelectedComponent (tab);
}*/
}
/** Helper method - closes given top component on all workspaces
* where it is opened */
private static void closeEverywhere (TopComponent tc) {
Workspace[] workspaces =
TopManager.getDefault().getWindowManager().getWorkspaces();
for (int i = 0; i < workspaces.length; i++) {
if (tc.isOpened(workspaces[i])) {
tc.close(workspaces[i]);
}
}
}
/** Utility method - returns list of workspaces where at least one from
* given list of top components is opened. */
private static List whereOpened (TopComponent[] tcs) {
Workspace[] workspaces =
TopManager.getDefault().getWindowManager().getWorkspaces();
ArrayList result = new ArrayList(workspaces.length);
for (int i = 0; i < workspaces.length; i++) {
for (int j = 0; j < tcs.length; j++) {
if (tcs[j].isOpened(workspaces[i])) {
result.add(workspaces[i]);
break;
}
}
}
return result;
}
/** @return List of "root" nodes which has following structure:<br>
* First goes repository, than root nodes added by modules and at last
* runtime root node */
private static List getRoots () {
Places.Nodes ns = TopManager.getDefault().getPlaces().nodes();
// build the list of roots
LinkedList result = new LinkedList();
// repository goes first
result.add(ns.repository());
// projects tab (only if projects module is installed)
if (NbProjectOperation.hasProjectDesktop()) {
result.add(NbProjectOperation.getProjectDesktop());
}
// roots added by modules (javadoc etc...)
result.addAll(Arrays.asList(ns.roots()));
// runtime
result.add(ns.environment());
return result;
}
/** Creates a top component dedicated to exploration of
* specified node, which will serve as root context */
private ExplorerTab createTC (Node rc) {
// switch according to the type of the root context
MainTab panel = null;
Places.Nodes ns = TopManager.getDefault().getPlaces().nodes();
if (rc.equals(NbProjectOperation.getProjectDesktop())) {
// projects tab
panel = new ProjectsTab();
} else if (rc.equals(ns.repository())) {
panel = new RepositoryTab ();
} else if (rc.equals(ns.environment())) {
// default tabs
panel = new MainTab();
} else {
// tabs added by modules
panel = new ModuleTab();
}
panel.setRootContext(rc);
rootsToTCs().put(rc, panel);
return panel;
}
/** Safe accessor for root context - top component map. */
private Map rootsToTCs () {
if (rootsToTCs == null) {
rootsToTCs = new HashMap(7);
}
return rootsToTCs;
}
/** Safe accessor for list of previous root nodes */
private List prevRoots () {
if (prevRoots == null) {
prevRoots = new LinkedList();
}
return prevRoots;
}
/** Deserialize this top component, sets as default.
* Provided provided here only for backward compatibility
* with older serialization protocol */
public void readExternal (ObjectInput in)
throws IOException, ClassNotFoundException {
super.readExternal(in);
//System.out.println("READING old main explorer..."); // NOI18N
// read explorer panels (and managers)
int cnt = in.readInt ();
for (int i = 0; i < cnt; i++) {
in.readObject();
}
in.readObject();
// read property sheet switcher state...
in.readBoolean ();
in.readBoolean ();
in.readInt();
in.readInt();
}
/** Finds the right panel for given node.
* @return the panel or null if no such panel exists
*/
final ExplorerTab getRootPanel (Node root) {
return (ExplorerTab)rootsToTCs().get(root);
}
// -------------------------------------------------------------------------
// Static methods
/** Static method to obtains the shared instance of NbMainExplorer
* @return the shared instance of NbMainExplorer
*/
public static NbMainExplorer getExplorer () {
if (explorer == null) {
explorer = new NbMainExplorer ();
}
return explorer;
}
/** @return The mode for main explorer on given workspace.
* Creates explorer mode if no such mode exists on given workspace */
private static Mode explorerMode (Workspace workspace) {
Mode result = workspace.findMode(WellKnownModeNames.EXPLORER);
if (result == null) {
// create explorer mode on current workspace
String displayName = NbBundle.getBundle(NbMainExplorer.class).
getString("CTL_ExplorerTitle");
result = workspace.createMode(
WellKnownModeNames.EXPLORER, displayName,
NbMainExplorer.class.getResource(
"/org/netbeans/core/resources/frames/explorer.gif" // NOI18N
)
);
}
return result;
}
/** Shared instance of NbMainExplorer */
private static NbMainExplorer explorer;
/** Common explorer top component which composites bean tree view
* to view given context. */
public static class ExplorerTab extends ExplorerPanel
implements DeferredPerformer.DeferredCommand {
static final long serialVersionUID =-8202452314155464024L;
/** composited view */
private TreeView view;
/** listeners to the root context and IDE settings */
private PropertyChangeListener rcListener, weakRcL, weakIdeL;
/** validity flag */
private boolean valid = true;
public ExplorerTab () {
super();
view = initGui();
// complete initialization of composited explorer actions
IDESettings ideS = (IDESettings)IDESettings.findObject(IDESettings.class);
setConfirmDelete(ideS.getConfirmDelete());
// attach listener to the changes of IDE settings
weakIdeL = WeakListener.propertyChange(rcListener(), ideS);
}
/** Initializes gui of this component. Subclasses can override
* this method to install their own gui.
* @return Tree view that will serve as main view for this explorer.
*/
protected TreeView initGui () {
TreeView view = new BeanTreeView();
setLayout(new BorderLayout());
add(view);
return view;
}
/** Request focus also for asociated view */
public void requestFocus () {
super.requestFocus();
view.requestFocus();
}
/** Ensures that component is valid before opening */
public void open (Workspace workspace) {
performCommand(null);
super.open(workspace);
}
/** Sets new root context to view. Name, icon, tooltip
* of this top component will be updated properly */
public void setRootContext (Node rc) {
// remove old listener, if possible
if (weakRcL != null) {
getExplorerManager().getRootContext().
removePropertyChangeListener(weakRcL);
}
getExplorerManager().setRootContext(rc);
initializeWithRootContext(rc);
}
public Node getRootContext () {
return getExplorerManager().getRootContext();
}
/** Overrides superclass version - adds request for initialization
* of the icon and other attributes, also re-attaches listener to the
* root context */
public void readExternal (java.io.ObjectInput oi)
throws java.io.IOException, ClassNotFoundException {
super.readExternal(oi);
// put a request for later validation
// we must do this here, because of ExplorerManager's deserialization.
// Root context of ExplorerManager is validated AFTER all other
// deserialization, so we must wait for it
valid = false;
WindowManagerImpl.deferredPerformer().putRequest(this, null);
}
/** Implementation of DeferredPerformer.DeferredCommand
* Performs initialization of component's attributes
* after deserialization (component's name, icon etc,
* according to the root context) */
public void performCommand (Object context) {
if (!valid) {
valid = true;
validateRootContext();
}
}
/** Validates root context of this top component after deserialization.
* It is guaranteed that this method is called at a time when
* getExplorerManager().getRootContext() call will return valid result.
* Subclasses can override this method and peform further validation
* or even set new root context instead of deserialized one.<br>
* Default implementation just initializes top component with standard
* deserialized root context. */
protected void validateRootContext () {
initializeWithRootContext(getExplorerManager().getRootContext());
}
private PropertyChangeListener rcListener () {
if (rcListener == null) {
rcListener = new RootContextListener();
}
return rcListener;
}
/** Initialize this top component properly with information
* obtained from specified root context node */
private void initializeWithRootContext (Node rc) {
// update TC's attributes
setIcon(rc.getIcon(BeanInfo.ICON_COLOR_16x16));
setToolTipText(rc.getShortDescription());
setName(rc.getDisplayName());
updateTitle();
// attach listener
if (weakRcL == null) {
weakRcL = WeakListener.propertyChange(rcListener(), rc);
}
rc.addPropertyChangeListener(weakRcL);
}
/** Multi - purpose listener, listens to: <br>
* 1) Changes of name, icon, short description of root context.
* 2) Changes of IDE settings, namely delete confirmation settings */
private final class RootContextListener extends Object
implements PropertyChangeListener {
public void propertyChange (PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
Object source = evt.getSource();
if (source instanceof IDESettings) {
// possible change in confirm delete settings
setConfirmDelete(((IDESettings)source).getConfirmDelete());
return;
}
// root context node change
Node n = (Node)source;
if (Node.PROP_DISPLAY_NAME.equals(propName) ||
Node.PROP_NAME.equals(propName)) {
setName(n.getDisplayName());
} else if (Node.PROP_ICON.equals(propName)) {
setIcon(n.getIcon(BeanInfo.ICON_COLOR_16x16));
} else if (Node.PROP_SHORT_DESCRIPTION.equals(propName)) {
setToolTipText(n.getShortDescription());
}
}
} // end of RootContextListener inner class
} // end of ExplorerTab inner class
/** Tab of main explorer. Tries to dock itself to main explorer mode
* before opening, if it's not docked already.
* Also deserialization is enhanced in contrast to superclass */
public static class MainTab extends ExplorerTab {
static final long serialVersionUID =4233454980309064344L;
/** Holds main tab which was last activated.
* Used during decision which tab should receive focus
* when opening all tabs at once using NbMainExplorer.openRoots()
*/
private static MainTab lastActivated;
public void open (Workspace workspace) {
Workspace realWorkspace = (workspace == null)
? TopManager.getDefault().getWindowManager().getCurrentWorkspace()
: workspace;
Mode ourMode = realWorkspace.findMode(this);
if (ourMode == null) {
explorerMode(realWorkspace).dockInto(this);
}
super.open(workspace);
}
/** Called when the explored context changes.
* Overriden - we don't want title to chnage in this style.
*/
protected void updateTitle () {
// empty to keep the title unchanged
}
/** Overrides superclass' version, remembers last activated
* main tab */
protected void componentActivated () {
super.componentActivated();
lastActivated = this;
}
/** Registers root context in main explorer in addition to superclass'
* version */
protected void validateRootContext () {
super.validateRootContext();
registerRootContext(getExplorerManager().getRootContext());
}
/* Add given root context and this top component
* to the map of main explorer's top components and nodes */
protected void registerRootContext (Node rc) {
NbMainExplorer explorer = NbMainExplorer.getExplorer();
explorer.prevRoots().add(rc);
explorer.rootsToTCs().put(rc, this);
}
} // end of MainTab inner class
/** Repository tab implements operation listener and
* if createFromTemplate is performed it selects the
* created node.
*/
public static class RepositoryTab extends MainTab
implements OperationListener {
static final long serialVersionUID =4233454980309064344L;
/** previous task */
private RequestProcessor.Task previousTask;
/** attaches itself to as a listener.
*/
public RepositoryTab () {
DataLoaderPool pool = TopManager.getDefault ().getLoaderPool ();
pool.addOperationListener (
WeakListener.operation (this, pool)
);
}
/** Object has been recognized by
* {@link DataLoaderPool#findDataObject}.
* This allows listeners
* to attach additional cookies, etc.
*
* @param ev event describing the action
*/
public void operationPostCreate (OperationEvent ev) {
}
/** Object has been successfully copied.
* @param ev event describing the action
*/
public void operationCopy (OperationEvent.Copy ev) {
}
/** Object has been successfully moved.
* @param ev event describing the action
*/
public void operationMove (OperationEvent.Move ev) {
}
/** Object has been successfully deleted.
* @param ev event describing the action
*/
public void operationDelete (OperationEvent ev) {
}
/** Object has been successfully renamed.
* @param ev event describing the action
*/
public void operationRename (OperationEvent.Rename ev) {
}
/** A shadow of a data object has been created.
* @param ev event describing the action
*/
public void operationCreateShadow (OperationEvent.Copy ev) {
}
/** New instance of an object has been created.
* @param ev event describing the action
*/
public void operationCreateFromTemplate (final OperationEvent.Copy ev) {
RequestProcessor.Task t = previousTask;
if (t != null) {
t.cancel ();
}
previousTask = RequestProcessor.postRequest (new Runnable () {
public void run () {
previousTask = null;
selectNode (ev.getObject ());
}
}, 2000);
}
/** Finds a node for given data object.
*/
private void selectNode (DataObject obj) {
Stack stack = new Stack ();
while (obj != null) {
stack.push (obj);
obj = obj.getFolder ();
}
Node current = getExplorerManager ().getRootContext ();
while (!stack.isEmpty ()) {
Node n = findDataObject (current, (DataObject)stack.pop ());
if (n == null) {
break;
}
current = n;
}
try {
getExplorerManager ().setSelectedNodes (new Node[] { current });
} catch (PropertyVetoException e) {
// you are out of luck!
throw new InternalError ();
}
}
/** Finds a data object in given node.
* @param node the node to search in
* @param obj the object to look for
*/
private static Node findDataObject (Node node, DataObject obj) {
Node n = node.getChildren ().findChild (obj.getNodeDelegate ().getName ());
if (n != null) return n;
Node[] arr = node.getChildren ().getNodes ();
for (int i = 0; i < arr.length; i++) {
if (obj == arr[i].getCookie (DataObject.class)) {
return arr[i];
}
}
return null;
}
}
/** Special class for projects tab in main explorer */
public static class ProjectsTab extends MainTab {
static final long serialVersionUID =-8178367548546385799L;
/** Exchanges deserialized root context to projects root context
* to keep the uniquennes. */
protected void validateRootContext () {
Node projectsRc = NbProjectOperation.getProjectDesktop();
setRootContext(projectsRc);
registerRootContext(projectsRc);
}
} // end of ProjectsTab inner class
/** Special class for tabs added by modules to the main explorer */
public static class ModuleTab extends MainTab {
static final long serialVersionUID =8089827754534653731L;
/** Throws deserialized root context and sets proper node found
* in roots set as new root context for this top component.
* The reason for such construction is to keep the uniquennes of
* root context node after deserialization. */
protected void validateRootContext () {
// find proper node
Class nodeClass = getExplorerManager().getRootContext().getClass();
Node[] roots = TopManager.getDefault().getPlaces().nodes().roots();
for (int i = 0; i < roots.length; i++) {
if (nodeClass.equals(roots[i].getClass())) {
setRootContext(roots[i]);
registerRootContext(roots[i]);
break;
}
}
}
} // end of ModuleTab inner class
/** Top component for project ang global settings. */
public static class SettingsTab extends ExplorerTab {
static final long serialVersionUID =9087127908986061114L;
/** Overrides superclass version - put tree view and property
* sheet to the splitted panel.
* @return Tree view that will serve as main view for this explorer.
*/
protected TreeView initGui () {
TreeView view = new BeanTreeView();
SplittedPanel split = new SplittedPanel();
PropertySheetView propertyView = new PropertySheetView();
split.add(view, SplittedPanel.ADD_LEFT);
split.add(propertyView, SplittedPanel.ADD_RIGHT);
// add to the panel
setLayout(new BorderLayout());
add(split, BorderLayout.CENTER);
return view;
}
/** Called when the explored context changes.
* Overriden - we don't want title to chnage in this style.
*/
protected void updateTitle () {
// empty to keep the title unchanged
}
}
/** Listener on roots, listens to changes of roots content */
private final class RootsListener extends Object
implements PropertyChangeListener {
public void propertyChange (PropertyChangeEvent evt) {
if (TopManager.PROP_PLACES.equals(evt.getPropertyName())) {
// possible change in list of roots
// defer refresh request if window system is in inconsistent state
WindowManagerImpl.deferredPerformer().
putRequest(NbMainExplorer.getExplorer(), null);
}
}
} // end of RootsListener inner class
public static void main (String[] args) throws Exception {
NbMainExplorer e = new NbMainExplorer ();
e.open ();
}
}
/*
* Log
* 54 Gandalf 1.53 1/19/00 Petr Nejedly Commented out debug
* messages
* 53 Gandalf 1.52 1/17/00 David Simonek renaming of tabs now
* react also on NAME node chaanges, not only display name
* 52 Gandalf 1.51 1/13/00 Jaroslav Tulach I18N
* 51 Gandalf 1.50 1/11/00 David Simonek projects tab now second
* tab in main explorer
* 50 Gandalf 1.49 1/9/00 David Simonek modified initialization
* of the WindowManagerImpl
* 49 Gandalf 1.48 1/5/00 Jaroslav Tulach Newly created objects are
* selected in explorer
* 48 Gandalf 1.47 12/23/99 David Simonek special tabs for projects
* and module tabs
* 47 Gandalf 1.46 12/21/99 David Simonek minor fixes
* 46 Gandalf 1.45 12/17/99 David Simonek #4886
* 45 Gandalf 1.44 12/3/99 David Simonek
* 44 Gandalf 1.43 11/30/99 David Simonek neccessary changes needed
* to change main explorer to new UI style (tabs are full top components
* now, visual workspace added, layout of editing workspace chnaged a bit)
* 43 Gandalf 1.42 11/5/99 Jesse Glick Context help jumbo patch.
* 42 Gandalf 1.41 11/5/99 Jaroslav Tulach WeakListener has now
* registration methods.
* 41 Gandalf 1.40 10/25/99 Ian Formanek Fixed title of Main
* Explorer - now displays selected node instead of explored context
* 40 Gandalf 1.39 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 39 Gandalf 1.38 10/7/99 David Simonek request focus related
* bugs repaired
* 38 Gandalf 1.37 9/22/99 Jaroslav Tulach Solving class cast
* exception.
* 37 Gandalf 1.36 9/20/99 Jaroslav Tulach #1603
* 36 Gandalf 1.35 9/15/99 David Simonek cut/copy/delete actions
* bugfix
* 35 Gandalf 1.34 8/29/99 Ian Formanek Removed obsoleted import
* 34 Gandalf 1.33 8/20/99 Ian Formanek Reverted last 2 changes
* 33 Gandalf 1.32 8/20/99 Ian Formanek Fixed bug with explorer
* when starting clean IDE
* 32 Gandalf 1.31 8/19/99 David Simonek cut/copy/paste/delete
* actions enabling hopefully fixed
* 31 Gandalf 1.30 8/18/99 David Simonek bugfix #3463, #3461
* 30 Gandalf 1.29 8/17/99 David Simonek commentaries removed
* 29 Gandalf 1.28 8/13/99 Jaroslav Tulach New Main Explorer
* 28 Gandalf 1.27 8/9/99 Ian Formanek Generated Serial Version
* UID
* 27 Gandalf 1.26 8/3/99 Jaroslav Tulach Getting better and
* better.
* 26 Gandalf 1.25 8/3/99 Jaroslav Tulach Serialization of
* NbMainExplorer improved again.
* 25 Gandalf 1.24 8/2/99 Jaroslav Tulach
* 24 Gandalf 1.23 8/1/99 Jaroslav Tulach MainExplorer now listens
* to changes in root elements.
* 23 Gandalf 1.22 7/30/99 David Simonek
* 22 Gandalf 1.21 7/30/99 David Simonek serialization fixes
* 21 Gandalf 1.20 7/28/99 David Simonek canClose updates
* 20 Gandalf 1.19 7/21/99 David Simonek properties switcher fixed
* 19 Gandalf 1.18 7/19/99 Jesse Glick Context help.
* 18 Gandalf 1.17 7/16/99 Ian Formanek Fixed bug #1800 - You can
* drag off the explorer toolbar.
* 17 Gandalf 1.16 7/15/99 Ian Formanek Swapped Global and
* Project settings tabs
* 16 Gandalf 1.15 7/13/99 Ian Formanek New MainExplorer tabs
* (usability&intuitiveness discussion results)
* 15 Gandalf 1.14 7/12/99 Jesse Glick Context help.
* 14 Gandalf 1.13 7/11/99 David Simonek window system change...
* 13 Gandalf 1.12 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 12 Gandalf 1.11 5/30/99 Ian Formanek Fixed bug 1647 - Open,
* Compile, Rename, Execute and etc. actions in popup menu in explorer are
* sometimes disabled. Fixed bug 1971 - If the tab is switched from
* Desktop to Repository with some nodes already selected, the actions in
* popupmenu might not be correctly enabled. Fixed bug 1616 - Property
* sheet button in explorer has no tooltip.
* 11 Gandalf 1.10 5/15/99 David Simonek switchable sheet
* serialized properly.....finally
* 10 Gandalf 1.9 5/14/99 David Simonek serialization of
* switchable sheet state
* 9 Gandalf 1.8 5/11/99 David Simonek changes to made window
* system correctly serializable
* 8 Gandalf 1.7 3/25/99 David Simonek another small changes in
* window system
* 7 Gandalf 1.6 3/25/99 David Simonek changes in window system,
* initial positions, bugfixes
* 6 Gandalf 1.5 3/18/99 Ian Formanek The title now updates
* when tab is switched
* 5 Gandalf 1.4 3/16/99 Ian Formanek SINGLE mode removed, as
* it is there by default
* 4 Gandalf 1.3 3/16/99 Ian Formanek Title improved
* 3 Gandalf 1.2 3/16/99 Ian Formanek Added listening to icon
* and displayName changes on roots, support for ExplorerActions
* (Cut/Copy/...)
* 2 Gandalf 1.1 3/15/99 Ian Formanek Added formatting of
* title, updating activatedNodes
* 1 Gandalf 1.0 3/14/99 Ian Formanek
* $
*/